package sysu.el.array;

import java.util.ArrayList;

import sysu.el.array.algors.MaxElem;
import sysu.el.array.ints.ArrInt;

/**
 * Make sure your set tag is smaller than the curMaxTagNum, 
 * and your applciation will be ok.
 * @author Edwin Lee
 *
 */

public class TagArray {

	public final static int UnTagValue = -1;
	
	private int tagArray[];
	private int size;
	private int zeroTag;
	
	public int curMaxTagNum;
	public int maxTag;
	
	public int size(){
		return size;
	}
	
	public void init(){
		this.zeroTag = Integer.MIN_VALUE + 1;
		for (int i=0; i<this.size; i++)
			this.tagArray[i] = Integer.MIN_VALUE;
	}
	
	public void reset(int maxTagsNum){
		if (zeroTag > Integer.MAX_VALUE - maxTagsNum){
			this.init();
		}else{
			this.zeroTag++;
		}
		curMaxTagNum = maxTagsNum;
		maxTag = -1;
		this.setMaxTag(maxTagsNum-1);
	}

	public void setMaxTag(int maxTag){
		this.maxTag = maxTag;
		if (maxTag >= curMaxTagNum){
			System.err.println("Error in MaxTag Setting.");
			if (zeroTag > Integer.MAX_VALUE - maxTag - 1){
				int off = Integer.MIN_VALUE + 1  - this.zeroTag;
				this.zeroTag = Integer.MIN_VALUE + 1;
				for (int i=0; i<tagArray.length; i++)
					if (tagArray[i] < this.zeroTag){
						tagArray[i] = Integer.MIN_VALUE;
					}else{
						tagArray[i] = tagArray[i] + off;
					}
			}
//			curMaxTagNum = zeroTag + maxTag + 1;
			curMaxTagNum = maxTag + 1;
		}
	}
	
	public TagArray(int size){
		this.size = size;
		this.tagArray = new int[size];
		/** int[] initial value is zero. It is guaranteed in Java Specification		 */
		this.zeroTag = 1;
		maxTag = -1;
		curMaxTagNum = 1;
//		this.init();
	}
	
	public int getTag(int i){
		int tag = this.tagArray[i] - this.zeroTag;
		if (tag < 0)
			return UnTagValue;
		else return tag;
	}
	
	public boolean isTag(int i){
		int tag = this.tagArray[i] - this.zeroTag;
		return (tag >= 0);
	}
	
	public boolean isNotTag(int i){
		int tag = this.tagArray[i] - this.zeroTag;
		return (tag < 0);
	}
	
	public void setTagDebug(int i, int tag){
		this.tagArray[i] = this.zeroTag + tag;
		if (tag > maxTag){
//			maxTag = tag;
			this.setMaxTag(tag);
		}
	}
	
	public void setTagCheck(int i, int tag){
		this.tagArray[i] = this.zeroTag + tag;
		if (tag > maxTag){
			maxTag = tag;
		}
	}
	
	/**
	 * If you decide to use this function.
	 * Then you'd better use getElemesWithTag with (int tagNum)
	 * @param i
	 * @param tag
	 */
	public void setTag(int i, int tag){
		this.tagArray[i] = this.zeroTag + tag;
	}
	
	public void setUntag(int i){
		this.tagArray[i] = this.zeroTag - 1;
	}
	
	/**
	 * There may be an error occurs, out of bound,
	 * because you have set a tag that is bigger than the tagNum
	 * @param tagNum
	 * @return
	 */
//	@Deprecated
	public ArrInt[] getElemsWithTag(int tagNum){
		ArrInt[] a = new ArrInt[tagNum];
		for (int i=0; i<tagNum; ++i)
			a[i] = new ArrInt(this.tagArray.length);
		for (int i=0; i<this.tagArray.length; ++i){
			int tag = this.getTag(i);
			if (tag >= tagNum) continue;
			if (tag != this.UnTagValue)
				a[tag].add(i);
		}
		return a;
	}
	
//	public ArrayList<ArrInt> getElemArrWithTag(int tagNum){
//		ArrayList<ArrInt> a = new ArrayList<ArrInt>(tagNum);
//		for (int i=0; i<tagNum; ++i)
//			a.set(i, new ArrInt(this.tagArray.length));
//		for (int i=0; i<this.tagArray.length; ++i){
//			int tag = this.getTag(i);
//			if (tag != this.UnTagValue)
//				a.get(tag).add(i);
//		}
//		return a;
//	}
//	
//	public ArrayList<ArrInt> getElemArrWithTag(){
//		if (maxTag != -1)
//			return getElemArrWithTag(maxTag + 1);
//		return getElemArrWithTag(this.curMaxTagNum);
//	}
	
	//@Deprecated
	public ArrInt[] getElemsWithTag(){
		if (maxTag != -1)
			return getElemsWithTag(maxTag + 1);
		return getElemsWithTag(this.curMaxTagNum);
	}
	
	public boolean equalTag(int i, int j){
		return (tagArray[i] == tagArray[j]);
	}
}
